<?php
// +----------------------------------------------------------------------
// | Menu 菜单服务
// +----------------------------------------------------------------------
// | 主要服务于Menu数据处理
// +----------------------------------------------------------------------
// | 错误编码头 232xxx
// +----------------------------------------------------------------------

namespace common\service;


use common\model\MenuModuleModel;
use common\model\MenuRouteModel;
use common\model\ProjectModel;
use common\model\ProjectTemplateModel;
use common\model\StepCategoryModel;
use Exception;
use support\ErrorCode;
use Throwable;

class MenuService
{
    /**
     * 临时方案 TODO 权限带增加
     *
     * | 角色名  | 角色编码  | 可以访问模块  | 默认模块  |
     * | ------------ | ------------ |------------ |------------ |
     * | 管理员  | admin | 运营后台、团队管理 | 运营后台 |
     * | 导演  | director | 工作台、项目管理、审片室、团队管理 | 工作台 |
     * | 制片人  | producer | 工作台、项目管理、团队管理、采购管理 | 工作台 |
     * | 组长 | headman  | 工作台、审片室、任务分配 | 工作台 |
     * | 艺术家 | artist  | 工作台 | 工作台 |
     *
     * @var array
     */
    protected $roleAllowModule = [
        'admin' => [ //管理员
            'default' => 'backend_manage',
            'list' => ['backend_manage', 'group_manage']
        ],
        'director' => [ //导演
            'default' => 'workbench',
            'list' => ['workbench', 'project_manage', 'audit', 'group_manage']
        ],
        'producer' => [//制片人
            'default' => 'workbench',
            'list' => ['workbench', 'project_manage', 'group_manage', 'purchase_manage', 'create_project', 'crm_management', 'authentication']
        ],
        'headman' => [//组长
            'default' => 'workbench',
            'list' => ['workbench', 'audit', 'task_assign']
        ],
        'artist' => [//艺术家
            'default' => 'workbench',
            'list' => ['workbench']
        ],
        'finance' => [//财务
            'default' => 'workbench',
            'list' => ['workbench', 'finance_manage']
        ]
    ];

    /**
     * 根据角色code来获取当前角色允许访问得模块
     * @param string $roleCode
     * @param array $menuModuleId
     * @param int $projectId
     * @return array
     */
    public function getRoleMenuModuleByCode($roleCode = '', $menuModuleId = [], $projectId = 0)
    {

        $currentTenantId = auto_fill_tenant_id();
        $tenantService = TenantService::getInstance();
        // 平台租户id
        $platTenantId = 0;
        try {
            $platTenantId = $tenantService->getPlatformTenantId();
        } catch (Throwable $e) {
            trace(format_exception_info($e), "ERR");
        }
        // 当前租户
        $tenant = $tenantAuthentication = null;
        try {
            $tenant = teamones_request('teamones-im', 'tenant/find', ['param' => ['filter' => ['id' => $currentTenantId]]])['data'];
            $requestData = ['param' => ['filter' => [
                'tenant_id' => $currentTenantId,
                'status' => 'active',
                'fdd_auth_status' => 4
            ]]];
            $tenantAuthentication = teamones_request('teamones-im', 'tenant_authentication/find', $requestData)['data'];
        } catch (Throwable $e) {
            trace(format_exception_info($e), "ERR");
        }
        //如果当前租户没有签署框架协议 并且不是绑定的平台租户 那么不显示采购 和crm模块

        // 进行删除操作前 copy 菜单
        $roleAllowModule = $this->roleAllowModule[$roleCode];
        if (empty($tenant) || ($tenant['id'] != $platTenantId && $tenant['framework_agreement_status'] != 'signed')) {
            foreach ($roleAllowModule['list'] as $key => $module) {
                if ($module == "purchase_manage" || $module == "crm_management") {
                    unset($roleAllowModule['list'][$key]);
                }
            }
            $roleAllowModule['list'] = array_values($roleAllowModule['list']);
        }

        //如果当前角色是财务 并且不是平台财务 需要过滤掉财务
        if ($roleCode == "finance" && array_key_exists($roleCode, $this->roleAllowModule) && isset($roleAllowModule['list']) && $platTenantId != auto_fill_tenant_id()) {
            foreach ($roleAllowModule['list'] as $key => $module) {
                if ($module == "finance_manage") {
                    unset($roleAllowModule['list'][$key]);
                }
            }
            $roleAllowModule['list'] = array_values($roleAllowModule['list']);
            unset($roleAllowModule);

        }
        if (!empty($roleCode) && array_key_exists($roleCode, $this->roleAllowModule)) {
            $moduleList = $roleAllowModule['list'];

            $menuModuleModel = model(MenuModuleModel::class);

            $queryFilter = [
                'code' => ['in', join(',', $moduleList)]
            ];

            if (!empty($menuModuleId)) {
                $queryFilter['id'] = ['IN', join(',', $menuModuleId)];
            }

            $menuModuleData = $menuModuleModel->field('id,name,code,icon')
                ->where($queryFilter)
                ->order('index asc')
                ->select();


            $menuModuleIds = array_column($menuModuleData, 'id');

            $defaultModuleRoute = [];

            if (!empty($menuModuleIds)) {
                // 获取当前模块默认访问得路由
                $menuRouteModel = model(MenuRouteModel::class);
                $menuRouteData = $menuRouteModel->field('id,name,menu_module_id,code,icon,route,index,is_show,type,is_default')
                    ->where([
                        'menu_module_id' => ['in', join(',', $menuModuleIds)]
                    ])
                    ->order('index asc')
                    ->select();

                if (!empty($menuRouteData)) {
                    //  如果传入项目信息 那么判断项目得类型  筛选固定菜单里需要隐藏得item
                    if ($projectId > 0) {
                        $project = model(ProjectModel::class)->where(['id' => $projectId])->field("module_codes,type")->find();
                        if ($project['type'] == "outsource") {
                            $dynamicRouteCode = explode(',', $project['module_codes']);
                            $menuRouteData = array_filter($menuRouteData, function ($item) use (&$dynamicRouteCode) {
                                //固定模块 筛选计划和清单
                                if ($item['type'] == "normal" && !in_array($item['code'], ['project_inventory', 'project_plan'])) {
                                    return true;
                                }
                                //动态模块 进行module_code筛选
                                if ($item['type'] == "dynamic" && in_array($item['code'], $dynamicRouteCode)) {
                                    return true;
                                }
                                return false;
                            });
                        }
                    }
                    // 回插默认访问路由

                    $menuRouteMap = [];
                    $menuRouteListMap = [];
                    foreach ($menuRouteData as $menuRouteItem) {

                        if ($menuRouteItem['code'] == 'personal_authorization' && empty($tenantAuthentication)) {
                            continue;
                        }
                        if (in_array((int)$menuRouteItem['index'], [0, 1])) {
                            $menuRouteMap[$menuRouteItem['menu_module_id']] = $menuRouteItem;
                        }

                        if (!empty($menuModuleId)) {
                            $menuRouteListMap[$menuRouteItem['menu_module_id']][] = $menuRouteItem;
                        }
                    }

                    $menuRouteMap = array_column($menuRouteData, null, 'menu_module_id');
                    $menuRouteGroupByModuleId = array_group_by($menuRouteData, 'menu_module_id');

                    foreach ($menuModuleData as &$menuItem) {
                        // 当前模块默认路由查询
                        $menuItem['default_route'] = null;
                        if (!empty($menuRouteGroupByModuleId[$menuItem['id']])) {
                            $defaultRouteList = array_filter($menuRouteGroupByModuleId[$menuItem['id']], function ($item) {
                                return $item['is_default'] == 'yes';
                            });
                            if (empty($defaultRouteList)) {
                                $menuItem['default_route'] = array_key_exists($menuItem['id'], $menuRouteMap) ? $menuRouteMap[$menuItem['id']] : [];
                            } else {
                                $menuItem['default_route'] = array_pop($defaultRouteList);
                            }
                        }

                        if (!empty($menuModuleId)) {
                            // 获取全部路由
                            $menuItem['route_list'] = array_key_exists($menuItem['id'], $menuRouteListMap) ? $menuRouteListMap[$menuItem['id']] : [];
                        }

                        if ($menuItem['code'] === $roleAllowModule['default']) {
                            $defaultModuleRoute = $menuItem;
                        }
                    }
                }
            }


            return ['default_module' => $defaultModuleRoute, 'module_list' => $menuModuleData];
        }


        return [];
    }


    /**
     * 通过路由查找模块名称
     * @param $param
     * @return array|mixed
     */
    public function getNameByRoute($param)
    {
        $roleCode = $param['filter']['role_code'];
        $route = $param['filter']['route'];
        $projectId = $param['filter']['project_id'] ?? 0;

        $menuRouteModel = model(MenuRouteModel::class);

        $menuModuleId = $menuRouteModel->where(['route' => $route])->getField('menu_module_id');

        if ($menuModuleId > 0) {
            $menuData = $this->getRoleMenuModuleByCode($roleCode, [$menuModuleId], $projectId);

            if (!empty($menuData) && is_array($menuData['module_list']) && count($menuData['module_list']) > 0) {
                $routeData = $menuData['module_list'][0];

                if ($routeData['code'] === 'project_manage') {
                    if (!empty($param['filter']['project_id'])) {
                        $this->getProjectRouteList($routeData['route_list'], $param['filter']['project_id']);
                    } else {
                        throw_strack_exception('project_id filter condition does not exist', ErrorCode::PROJECT_ID_FILTER_PARAM_REQUIRE);
                    }
                }

                return $routeData;
            }
        }

        return [];
    }


    /**
     * 更新菜单模块排序索引
     * @param $data
     * @return array
     */
    public function setMenuModuleIndex($data)
    {
        $updateData = [];

        $menuModuleModel = model(MenuModuleModel::class);
        $menuModuleModel->startTrans();
        try {
            foreach ($data as $item) {
                if (array_key_exists('id', $item) && array_key_exists('index', $item)) {
                    $updateData[] = $item;
                    $menuModuleModel->save($item);
                } else {
                    throw new Exception('Incorrect data format.', ErrorCode::INCORRECT_DATA_FORMAT);
                }
            }
            $menuModuleModel->commit();
        } catch (Exception $exception) {
            $menuModuleModel->rollback();
            throw_strack_exception($exception->getMessage(), $exception->getCode());
        }

        return $updateData;
    }

    /**
     * 更新菜单路由排序索引
     * @param $data
     * @return array
     */
    public function setMenuRouteIndex($data)
    {
        $updateData = [];

        $menuRouteModel = model(MenuRouteModel::class);
        $menuRouteModel->startTrans();
        try {
            foreach ($data as $item) {
                if (array_key_exists('id', $item) && array_key_exists('index', $item)) {
                    $updateData[] = $item;
                    $menuRouteModel->save($item);
                } else {
                    throw new Exception('Incorrect data format.', ErrorCode::INCORRECT_DATA_FORMAT);
                }
            }
            $menuRouteModel->commit();
        } catch (Exception $exception) {
            $menuRouteModel->rollback();
            throw_strack_exception($exception->getMessage(), $exception->getCode());
        }

        return $updateData;
    }

    /**
     * 获取路由列表
     * @param $filter
     * @param $currentTenantId
     * @return array|mixed
     * @throws Exception
     */
    public function getRouteList($filter, $currentTenantId)
    {
        $filter['project_id'] = $filter['project_id'] ?? 0;
        $menuRouteData = $this->getFixedRouteList($filter['menu_module'], $filter['project_id']);

        if ($filter['menu_module'] === 'project_manage' && $filter['project_id'] > 0) {
            // 查询项目动态模块
            $this->getProjectRouteList($menuRouteData, $filter['project_id']);
        }
        // 当前租户
        $tenantAuthentication = null;
        try {
            $requestData = ['param' => ['filter' => [
                'tenant_id' => $currentTenantId,
                'status' => 'active',
                'fdd_auth_status' => 4
            ]]];
            $tenantAuthentication = teamones_request('teamones-im', 'tenant_authentication/find', $requestData)['data'];
        } catch (Throwable $e) {
            trace(format_exception_info($e), "ERR");
        }

        if (!empty($menuRouteData)) {
            foreach ($menuRouteData as $key => $menuRouteItem) {
                if ($menuRouteItem['code'] == 'personal_authorization' && empty($tenantAuthentication)) {
                    unset($menuRouteData[$key]);
                }
            }
            $menuRouteData = array_values($menuRouteData);
        }

        return $menuRouteData;
    }


    /**
     * 获取模块固定路由
     * @param $menuModuleCode
     * @param int $projectId
     * @return array|mixed
     */
    public function getFixedRouteList($menuModuleCode, $projectId = 0)
    {
        // 获取固定模块，排序为第一个的为默认模块
        $menuModuleModel = model(MenuModuleModel::class);
        $menuModuleId = $menuModuleModel->where(['code' => $menuModuleCode])->getField('id');

        $menuRouteModel = model(MenuRouteModel::class);
        $menuRouteData = $menuRouteModel->field('id,name,menu_module_id,code,icon,route,is_show,type')
            ->where(['menu_module_id' => $menuModuleId])
            ->order('index asc')
            ->select();

        //  如果传入项目信息 那么判断项目得类型  筛选固定菜单里需要隐藏得item
        if ($projectId > 0) {
            $project = model(ProjectModel::class)->where(['id' => $projectId])->field("module_codes,type")->find();
            if ($project['type'] == "outsource") {
                $menuRouteData = array_filter($menuRouteData, function ($item) {
                    return !in_array($item['code'], ['project_inventory']);
                });
            }
        }

        if (!empty($menuRouteData)) {
            return $menuRouteData;
        }

        return [];
    }

    /**
     * 获取项目路由列表
     * @param $menuRouteData
     * @param $projectId
     * @return array
     */
    public function getProjectRouteList(&$menuRouteData, $projectId)
    {

        // 获取非固定模块
        // 1. 获取项目模板配置
        $projectTemplateModel = model(ProjectTemplateModel::class);
        $projectTemplateConfigData = $projectTemplateModel->alias('project_temp')
            ->join('LEFT JOIN project ON project.project_template_id = project_temp.id')
            ->where(['project.id' => $projectId])
            ->field('project_temp.config')
            ->find();
        $projectModel = model(ProjectModel::class);
        $project = $projectModel->find($projectId);

        if (!empty($projectTemplateConfigData)) {
            $projectTemplateConfig = json_decode($projectTemplateConfigData['config'], true);

            if (!empty($projectTemplateConfig['step_category_plan']['tasks'])) {
                // 工序资产分类map
                $stepCategoryModel = model(StepCategoryModel::class);
                $stepCategoryData = $stepCategoryModel->field('id,name,code')->where(['parent_id' => 0, 'entity_id' => ['NEQ', 0]])->select();

                $stepCategoryMap = array_column($stepCategoryData, null, 'id');

                $dynamicRouteCode = [];

                if ($project['type'] == "outsource") {
                    //外部项目 直接使用项目里得module_codes
                    $dynamicRouteCode = explode(',', $project['module_codes']);
                } else {
                    // 查找当前项目模板配置的实体code 组合动态模块code
                    array_map(function (&$item) use (&$stepCategoryMap, &$dynamicRouteCode) {
                        if ((int)$item['parent_id'] !== 0) {
                            return false;
                        }
                        $dynamicRouteCode[] = $stepCategoryMap[$item['id']]['code'];
                        return true;
                    }, $projectTemplateConfig['step_category_plan']['tasks']);
                }


                //匹配路由
                $menuRouteData = array_filter($menuRouteData, function ($item) use ($dynamicRouteCode) {
                    if (isset($item['type']) && isset($item['code']) && $item['type'] == "dynamic") {
                        return in_array($item['code'], $dynamicRouteCode);
                    }
                    return true;
                });
                // 防止index缺失 变成object
                $menuRouteData = array_values($menuRouteData);
            }
        }

        return $menuRouteData;
    }
}
